package com.powergisol.gis.service.impl;

import com.powergisol.gis.service.ChangeMapService;
import com.powergisol.gis.service.FileAnsyc;
import com.powergisol.gis.service.IFileService;
import com.powergisol.gis.service.ServiceUploadService;
import com.powergisol.gis.util.FileList;
import com.powergisol.gis.util.PropertyUtil;
import com.powergisol.gis.util.Result;
import com.powergisol.gis.util.ZipUtil;
import com.powergisol.gis.vo.TabServiceVo;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class ServiceUploadServiceImpl implements ServiceUploadService {
    private static Logger logger = LoggerFactory.getLogger(ServiceUploadServiceImpl.class);

    @Value("${collectionName}")
    private String collectionName;
    @Autowired
    private ChangeMapService changeMapService;

    @Autowired
    private IFileService fileService;
    @Autowired
    private FileAnsyc fileAnsyc;

    @Autowired
    private RedisTemplate redisTemplate;
//    @Value("${file-url}")
//    private String fileUrl;
    @Value("${expira_time}")
    private Integer expiraTime;


    @Override
    @Async
    public void unZiphThread(Map<String,Object> resultMap,TabServiceVo vo){
        //logger.info("解压开始={}",vo.getName());
        //2、解压文件
        String uniqFlag = "formal" + File.separator + vo.getAssinSuffixName() + File.separator +vo.getUuid()+File.separator+vo.getName() + File.separator;
        String userDir = System.getProperty("user.dir");
        userDir = userDir.substring(0,userDir.lastIndexOf(File.separator));
        String unZipPath = userDir+File.separator+"serviceData" + File.separator + uniqFlag;
        try {
            ZipFile zFile = new ZipFile(resultMap.get("destUrl").toString());
            // 设置文件名编码，在GBK系统中需要设置
            zFile.setFileNameCharset("GBK");
            if (zFile.isValidZipFile()) {
                //先解压文件
                Result result = ZipUtil.unZip(resultMap.get("destUrl").toString(),unZipPath);
                if(result.getCode()!=0){
                    //logger.error("解压文件失败：{}",vo.getName(),result.getMsg());
                    redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg","解压异常",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","-1",expiraTime,TimeUnit.HOURS);
                    return;
                }
            }
        } catch (ZipException e) {
            //logger.error("解压文件失败：{}",vo.getName(),e.getMessage());
            redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg","解压异常",expiraTime,TimeUnit.HOURS);
            redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","-1",expiraTime,TimeUnit.HOURS);
            return;
        }
        redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","100",expiraTime,TimeUnit.HOURS);
        logger.info("解压结束={}",vo.getName());
        Result result = new Result();
        switch (vo.getServiceType()){
            //不需保存转换、入库
            case 1://影像缓存文件（*.tif）
            case 4://矢量缓存文件（*.shp）
                result = FileList.fileRead(unZipPath,vo.getAssinSuffixName());
                if(0!=result.getCode()){
                    redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","-1",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg",result.getMsg(),expiraTime,TimeUnit.HOURS);
                    logger.error("获取文件list失败：{}",vo.getName(),result.getMsg());
                    return;
                }
                resultMap = (Map<String,Object>)result.getData();
                redisTemplate.opsForValue().set(vo.getUuid()+"Out",resultMap.get("fileUrl").toString(),expiraTime,TimeUnit.HOURS);
                redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","100",expiraTime,TimeUnit.HOURS);

//                List<File> fileList14 = ( List<File>)resultMap.get("listFile");
//                //expiraTime、保存入库
//                String path14 = resultMap.get("fileUrl").toString().replace("/",File.separator);
//                try {
//                    saveFileToDb(fileList14,vo.getUuid(),vo.getName(),path14);
//                    logger.info("入库完成={}",vo.getName());
//                }catch (Exception e){
//                    logger.error("文件保存失败：{}",vo.getName());
//                    return;
//                }
                break;
            //入库
            case 2://高程缓存文件（*.terrain）
                //3、获取待处理文件list
                logger.info("入库开始={}",vo.getName());
                result = FileList.fileRead(unZipPath,vo.getAssinSuffixName());
                if(0!=result.getCode()){
                    redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","-1",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg",result.getMsg(),expiraTime,TimeUnit.HOURS);
                    logger.error("获取文件list失败：{}",vo.getName(),result.getMsg());
                    return;
                }
                resultMap = (Map<String,Object>)result.getData();
                List<File> fileList2 = ( List<File>)resultMap.get("listFile");
                redisTemplate.opsForValue().set(vo.getUuid()+"Out",resultMap.get("fileUrl").toString(),expiraTime,TimeUnit.HOURS);
                redisTemplate.opsForValue().set(vo.getUuid()+"TotalSize",fileList2.size(),expiraTime,TimeUnit.HOURS);
                //expiraTime、保存入库
                String path2 = resultMap.get("fileUrl").toString().replace("/",File.separator);
                try {
                    saveFileToDb(fileList2,vo.getUuid(),vo.getName(),path2);
                    logger.info("入库完成={}",vo.getName());
                }catch (Exception e){
                    redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","-1",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg","保存异常",expiraTime,TimeUnit.HOURS);
                    logger.error("文件保存失败：{}",vo.getName());
                    return;
                }
                break;
            case 5://b3dm三维模型文件（*.json）
            case 8://lob三维模型文件（*.json）
                //3、获取待处理文件list
                logger.info("入库开始={}",vo.getName());
                result = FileList.fileRead(unZipPath,vo.getAssinSuffixName());
                if(0!=result.getCode()){
                    redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","-1",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg",result.getMsg(),expiraTime,TimeUnit.HOURS);
                    logger.error("获取文件list失败：{}",vo.getName(),result.getMsg());
                    return;
                }
                resultMap = (Map<String,Object>)result.getData();
                List<File> fileList = ( List<File>)resultMap.get("listFile");
                redisTemplate.opsForValue().set(vo.getUuid()+"Out",resultMap.get("fileUrl").toString(),expiraTime,TimeUnit.HOURS);
                redisTemplate.opsForValue().set(vo.getUuid()+"TotalSize",fileList.size(),expiraTime,TimeUnit.HOURS);
                //expiraTime、保存入库
                String path = resultMap.get("fileUrl").toString().replace("/",File.separator);
                try {
                    saveFileToDb(fileList,vo.getUuid(),vo.getName(),path.substring(0,path.lastIndexOf(File.separator)));
                    logger.info("入库完成={}",vo.getName());
                }catch (Exception e){
                    redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","-1",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg","保存异常",expiraTime,TimeUnit.HOURS);
                    logger.error("文件保存失败：{}",vo.getName());
                    return;
                }
                break;
            case 6://osgb三维模型文件（*.xml）
                //3、获取待处理文件list
                result = FileList.fileRead(unZipPath,"xml");
                if(0!=result.getCode()){
                    redisTemplate.opsForValue().set(vo.getUuid()+"ExchangeProgress","-0.01",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg",result.getMsg(),expiraTime,TimeUnit.HOURS);
                    logger.error("获取文件list失败：{}",vo.getName(),result.getMsg());
                    return;
                }
                resultMap = (Map<String,Object>)result.getData();
                List<File> fileList6 = ( List<File>)resultMap.get("listFile");
                redisTemplate.opsForValue().set(vo.getUuid()+"TotalSize",fileList6.size(),expiraTime,TimeUnit.HOURS);
                //expiraTime、转换
                String in = resultMap.get("fileUrl").toString().substring(0,resultMap.get("fileUrl").toString().lastIndexOf(File.separator));
                String out = in.replace("formal","change");
                redisTemplate.opsForValue().set(vo.getUuid()+"In",in,expiraTime,TimeUnit.HOURS);
                redisTemplate.opsForValue().set(vo.getUuid()+"Out",out,expiraTime,TimeUnit.HOURS);
                logger.info("{}转换开始,输入={},输出={}",vo.getName(),in,out);
                if("pld".equals(vo.getChangeType())){
                    try{
                        changeMapService.osgbToPld(in,out);
                    }catch (Exception e){
                        logger.error("osgb2b3dmNew异常={}",vo.getName());
                    }
                }else if("b3dm".equals(vo.getChangeType())){
                   try{
                       changeMapService.osgb2b3dmNew(in,out);
                   }catch (Exception e){
                       logger.error("osgb2b3dmNew异常={}",vo.getName());
                   }
                }
                break;
            case 7:
                //3、获取待处理文件list
                result = FileList.fileRead(unZipPath,vo.getAssinSuffixName());
                if(0!=result.getCode()){
                    redisTemplate.opsForValue().set(vo.getUuid()+"ExchangeProgress","-0.01",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg",result.getMsg(),expiraTime,TimeUnit.HOURS);
                    logger.error("获取文件list失败：{}",vo.getName(),result.getMsg());
                    return;
                }
                resultMap = (Map<String,Object>)result.getData();
                List<File> fileList7 = ( List<File>)resultMap.get("listFile");
                redisTemplate.opsForValue().set(vo.getUuid()+"TotalSize",fileList7.size(),expiraTime,TimeUnit.HOURS);
                //expiraTime、转换
                String in7 = resultMap.get("fileUrl").toString();
                String out7 = resultMap.get("fileUrl").toString().replace("formal","change").replace("obj","glb");
                redisTemplate.opsForValue().set(vo.getUuid()+"In",in7,expiraTime,TimeUnit.HOURS);
                redisTemplate.opsForValue().set(vo.getUuid()+"Out",out7,expiraTime,TimeUnit.HOURS);
                logger.info("{} 开始转换,输入={},输出={}",vo.getName(),in7,out7);
                try{
                    changeMapService.objToGltf(in7,out7);
                }catch (Exception e){
                    logger.error("objToGltf异常={}",vo.getName());
                }
                break;
            case 3://高程缓存文件（*.tif）
                //如果转换类型为terrain则需要进行转换
                if("terrain".equals(vo.getChangeType())){
                    result = FileList.fileRead(unZipPath,vo.getAssinSuffixName());
                    if(0!=result.getCode()){
                        redisTemplate.opsForValue().set(vo.getUuid()+"ExchangeProgress","-0.01",expiraTime,TimeUnit.HOURS);
                        redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg",result.getMsg(),expiraTime,TimeUnit.HOURS);
                        logger.error("获取文件list失败：{}",vo.getName(),result.getMsg());
                        return;
                    }
                    resultMap = (Map<String,Object>)result.getData();
                    List<File> fileList3 = ( List<File>)resultMap.get("listFile");
                    redisTemplate.opsForValue().set(vo.getUuid()+"TotalSize",fileList3.size(),expiraTime,TimeUnit.HOURS);
                    //expiraTime、转换
                    String in3 = resultMap.get("fileUrl").toString();
                    String out3 = userDir+File.separator+"serviceData"+File.separator+"change"+File.separator+"json"+File.separator+vo.getUuid();
                    //将tif文件移至转换路径中，便于读取服务属性
//                    try {
//                        fileAnsyc.copyByChannelToChannel(in3,fileUrl+File.separator+"formal"+File.separator+"tif"+File.separator+vo.getUuid()+File.separator+"layer.tif");
//                        //FileCopy.copy(new File(in3),new File(fileUrl+File.separator+"formal"+File.separator+"tif"+File.separator+vo.getUuid()+File.separator+"layer.tif"));
//                    } catch (IOException e) {
//                        e.printStackTrace();
//                    }
                    redisTemplate.opsForValue().set(vo.getUuid()+"In",in3,expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"Out",out3.substring(0,out3.lastIndexOf(File.separator)),expiraTime,TimeUnit.HOURS);
                    logger.info("{} 开始转换,输入={},输出={}",vo.getName(),in3,out3);
                    try{
                        changeMapService.tif2terrain(in3,out3,vo.getStartLevel(),vo.getEndLevel());
                    }catch (Exception e){
                        logger.error("tif2terrain异常={}",vo.getName());
                    }
                    redisTemplate.opsForValue().set(vo.getUuid()+"Out",out3,expiraTime,TimeUnit.HOURS);
                }else{//转换类型为tif不转换、不存库
                    result = FileList.fileRead(unZipPath,vo.getAssinSuffixName());
                    if(0!=result.getCode()){
                        redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","-1",expiraTime,TimeUnit.HOURS);
                        redisTemplate.opsForValue().set(vo.getUuid()+"ErrorMsg",result.getMsg(),expiraTime,TimeUnit.HOURS);
                        logger.error("获取文件list失败：{}",vo.getName(),result.getMsg());
                        return;
                    }
                    resultMap = (Map<String,Object>)result.getData();
                    redisTemplate.opsForValue().set(vo.getUuid()+"Out",resultMap.get("fileUrl").toString(),expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","100",expiraTime,TimeUnit.HOURS);
//                    List<File> fileList3 = ( List<File>)resultMap.get("listFile");
//                    //expiraTime、保存入库
//                    String path3 = resultMap.get("fileUrl").toString().replace("/",File.separator);
//                    try {
//                        saveFileToDb(fileList3,vo.getUuid(),vo.getName(),path3);
//                        logger.info("入库完成={}",vo.getName());
//                    }catch (Exception e){
//                        logger.error("文件保存失败：{}",vo.getName());
//                        return;
//                    }
                }

                break;
        }
    }
    /**
     * 保存入库
     * @param file
     * @param uuid
     * @param serviceName
     * @param path
     */
    @Override
    public void saveFileToDb(List<File> file,String uuid,String serviceName,String path){
        if(null == file || file.size()==0){
            return;
        }
        Integer totalSize = file.size();
        Integer maxNum = 1000;
        if(totalSize>20000 && totalSize<=100000){
            maxNum = 5000;
        }else if(totalSize>100000 && totalSize<=200000){
            maxNum = 10000;
        }else if(totalSize>200000 && totalSize<=1000000){
            maxNum = 50000;
        }else if(totalSize>1000000){
            maxNum = 100000;
        }

        int num = (file.size()/maxNum)+(file.size()%maxNum>0?1:0);
        logger.info("文件数量："+file.size()+";循环次数："+num);
        for (int i = 0; i < num; i++) {
            List<File> files = null;
            if((i+1)==num){
                files = file.subList(i*maxNum,file.size());
            }else{
                files = file.subList(i*maxNum,(i+1)*maxNum);
            }
            fileService.saveDb(files,uuid,serviceName,path.substring(0, path.lastIndexOf(File.separator)),i);

        }
    }

    /**
     * 选择文件操作
     * @param vo
     */
    @Override
    @Async
    public void selectFileSave(TabServiceVo vo,Result result){
        Map<String,Object> resultMap = null;
        String in;
        String out;
        String userDir = System.getProperty("user.dir");
        userDir = userDir.substring(0,userDir.lastIndexOf(File.separator));
        try{
            switch (vo.getServiceType()){
                //大文件不需要存库
                case 1://影像缓存文件（*.tif）
                case 4://矢量缓存文件（*.shp）
                    redisTemplate.opsForValue().set(vo.getUuid() + "Out", vo.getFileUrl(),expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","100",expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","100",expiraTime,TimeUnit.HOURS);

//                    result = FileList.fileReadSameName(vo.getFileUrl());
//
//                    List<File> fileList14 = (List<File>)result.getData();
//                    //expiraTime、保存入库
//                    String path14 = vo.getFileUrl().replace("/",File.separator);
//                    try {
//                        saveFileToDb(fileList14,vo.getUuid(),vo.getName(),path14);
//                        logger.info("入库完成={}",vo.getName());
//                    }catch (Exception e){
//                        logger.error("文件保存失败：{}",vo.getName());
//                        return;
//                    }

                    break;
                case 2://高程缓存文件（*.terrain）
                    String path2 = vo.getFileUrl();
                    redisTemplate.opsForValue().set(vo.getUuid() + "Out", path2,expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","100",expiraTime,TimeUnit.HOURS);
                    result = FileList.fileRead(vo.getFileUrl(),vo.getAssinSuffixName());
                    resultMap = (Map<String,Object>)result.getData();
                    List<File> fileList2 = ( List<File>)resultMap.get("listFile");
                    redisTemplate.opsForValue().set(vo.getUuid()+"TotalSize",fileList2.size(),expiraTime,TimeUnit.HOURS);
                    //保存入库
                    logger.info("入库开始={}",vo.getUuid());
                    this.saveFileToDb(fileList2,vo.getUuid(),vo.getName(),path2);
                    break;
                case 5://b3dm三维模型文件（*.json）
                case 8://lob三维模型文件（*.json）
                    String path = vo.getFileUrl();
                    redisTemplate.opsForValue().set(vo.getUuid() + "Out", path,expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","100",expiraTime,TimeUnit.HOURS);
                    result = FileList.fileRead(vo.getFileUrl(),vo.getAssinSuffixName());
                    resultMap = (Map<String,Object>)result.getData();
                    List<File> fileList = ( List<File>)resultMap.get("listFile");
                    redisTemplate.opsForValue().set(vo.getUuid()+"TotalSize",fileList.size(),expiraTime,TimeUnit.HOURS);
                    //保存入库
                    logger.info("入库开始={}",vo.getUuid());
                    this.saveFileToDb(fileList,vo.getUuid(),vo.getName(),path.substring(0,path.lastIndexOf(File.separator)));
                    break;
                case 6://osgb三维模型文件（*.xml）
                    redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","100",expiraTime,TimeUnit.HOURS);
                    //4、转换
                    String getFileUrl = vo.getFileUrl();
                    in = getFileUrl.substring(0,getFileUrl.lastIndexOf(File.separator));
                    out = userDir+File.separator+"serviceData"+File.separator+"change"+File.separator+"json"+File.separator+vo.getUuid();
                    redisTemplate.opsForValue().set(vo.getUuid()+"In",in,expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"Out",out,expiraTime,TimeUnit.HOURS);
                    logger.info("{}转换开始,输入={},输出={}",vo.getName(),in,out);
                    if("pld".equals(vo.getChangeType())){
                        try{
                            changeMapService.osgbToPld(in,out);
                        }catch (Exception e){
                        }
                    }else if("b3dm".equals(vo.getChangeType())){
                        try{
                            changeMapService.osgb2b3dmNew(in,out);
                        }catch (Exception e){
                        }
                    }
                    break;
                case 7://obj三维模型文件（*.obj）
                    redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","100",expiraTime,TimeUnit.HOURS);
                    //4、转换
                    in = vo.getFileUrl();
                    out = userDir+File.separator+"serviceData"+File.separator+"change"+File.separator+"glb"+File.separator+vo.getUuid()+File.separator+"objToGlb.glb";
                    redisTemplate.opsForValue().set(vo.getUuid()+"In",in,expiraTime,TimeUnit.HOURS);
                    redisTemplate.opsForValue().set(vo.getUuid()+"Out",out,expiraTime,TimeUnit.HOURS);
                    logger.info("{}转换开始,输入={},输出={}",vo.getName(),in,out);
                    try{
                        changeMapService.objToGltf(in,out);
                    }catch (Exception e){
                    }
                    break;
                case 3://高程缓存文件（*.tif）
                    if("terrain".equals(vo.getChangeType())){
                        redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","100",expiraTime,TimeUnit.HOURS);
                        //4、转换
                        in = vo.getFileUrl();
                        out = userDir+File.separator+"serviceData"+File.separator+"change"+File.separator+"json"+File.separator+vo.getUuid();
                        //将tif文件移至转换路径中，便于读取服务属性
                       // fileAnsyc.copyByChannelToChannel(in,fileUrl+File.separator+"formal"+File.separator+"tif"+File.separator+vo.getUuid()+File.separator+"layer.tif");
                        //FileCopy.copy(new File(in),new File(fileUrl+File.separator+"formal"+File.separator+"tif"+File.separator+vo.getUuid()+File.separator+"layer.tif"));
                        redisTemplate.opsForValue().set(vo.getUuid()+"In",in,expiraTime,TimeUnit.HOURS);
                        redisTemplate.opsForValue().set(vo.getUuid()+"Out",out,expiraTime,TimeUnit.HOURS);
                        logger.info("{}转换开始,输入={},输出={}",vo.getName(),in,out);
                        try{
                            changeMapService.tif2terrain(in,out,vo.getStartLevel(),vo.getEndLevel());
                        }catch (Exception e){
                            logger.info("tif2terrain转换路径：{}，{}",in,out);
                        }
                    }else{
                        redisTemplate.opsForValue().set(vo.getUuid() + "Out", vo.getFileUrl(),expiraTime,TimeUnit.HOURS);
                        redisTemplate.opsForValue().set(vo.getUuid()+"UnzipProgress","100",expiraTime,TimeUnit.HOURS);
                        redisTemplate.opsForValue().set(vo.getUuid()+"SaveProgress","100",expiraTime,TimeUnit.HOURS);

//                        result = FileList.fileReadSameName(vo.getFileUrl());
//
//                        List<File> fileList3 = (List<File>)result.getData();
//                        //expiraTime、保存入库
//                        String path3 = vo.getFileUrl().replace("/",File.separator);
//                        try {
//                            saveFileToDb(fileList3,vo.getUuid(),vo.getName(),path3);
//                            logger.info("入库完成={}",vo.getName());
//                        }catch (Exception e){
//                            logger.error("文件保存失败：{}",vo.getName());
//                            return;
//                        }
                    }
                    break;
                default:
                    break;
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.info("选择文件入库失败:{}",e.getMessage());
        }
    }
}
